﻿using System;
using System.Windows;
using Shoozla.ViewModel;
using Shoozla.View;
using System.Threading;
using Shoozla.DataModel;
using System.IO;
using System.Diagnostics;
using Shoozla.DataModel.Helper;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Reflection;
using MahApps.Metro.Controls;
using System.Collections.ObjectModel;


namespace Shoozla
{

    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : System.Windows.Application
    {
        #region Enums
       
        public enum StartingMode
        { 
            Visual,
            Background
        }

        #endregion

        #region  Variables              

        public static String LogFileName = "shoozla-log.txt";
        public static String EventSourceName = "Shoozla";
        public static bool EventSourceCreated = false;

        public static StatisticsLogger StatisticLogger;
        public static TxtTraceListener Tracer;

        //views
        public static FolderListView FolderView;
        public static MainView MainView;

       
        #endregion

        protected override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);           
        }

        
        /// <summary>
        /// Main method, initialize all the variables and event callbacks
        /// </summary>
        /// <param name="e"></param>
        protected override void OnStartup(StartupEventArgs e)
        {
            //update statistics webservice
            //it will log only the IP + Datetime, for stat usages

#if !DEBUG
            Task.Factory.StartNew(() =>
            {
                try
                {
                    StatisticsService.UsageStatisticsClient statClient = new StatisticsService.UsageStatisticsClient();
                    statClient.SoftwareStarted();
                }
                catch
                {
                    //do nothing
                }
            });           
#endif
            

            base.OnStartup(e);
            
            AppModel.Songs = new ObservableCollection<Mp3File>();
            

            AppModel.MainCancellationTokenSource = new CancellationTokenSource();
            AppModel.ProgressOperationQueue = new ObservableCollection<IProgressOperation>();
            AppModel.ProgressOperationQueue.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(AppModel.ProgressOperationQueue_CollectionChanged);

            AppModel.FoldersSelected = new List<DirectoryInfo>();
            Tracer = new TxtTraceListener(App.LogFileName);
          
            StatisticLogger = new StatisticsLogger();    
            AppModel.Mp3Processor = new IDSharpProcessor();
            AppModel.CoverImageCache = new InternetCoverStorage(AppModel.MainCancellationTokenSource);

            AppModel.TagsSearcher = new EchonestTagsSearcher(AppModel.MainCancellationTokenSource, StatisticLogger);
            AppModel.TagsSearcher.Completed += new EventHandler<ProgressOperationEventArgs>(AppModel.IProgressOperation_SearchCompleted);
            AppModel.TagsSearcher.Started += new EventHandler<ProgressOperationEventArgs>(AppModel.IProgressOperation_SearchStarted);

            FindCoverSearchersAddIn();

            AppModel.LogEntry(DateTime.Now.ToLocalTime() + " | Shoozla started");


            //single-instance application
            bool mutexIsNew;
            using (Mutex m = new Mutex(true, "Shoozla", out mutexIsNew))
            {
                if (mutexIsNew)
                {
                    try
                    {
                        //first instance
                        switch (CheckStartingMode())
                        {
                            case StartingMode.Visual: { StartUI(); break; }
                            case StartingMode.Background: { StartBackground(); break; }
                        }
                    }
                    catch(Exception ue)
                    {
#if DEBUG
                        MessageBox.Show("Execption: " + ue.Message);
                        MessageBox.Show(ue.StackTrace);
#endif
                        AppModel.LogEntry("[EX] Unhandled Exception: " + ue.Message);
                        AppModel.LogEntry(ue.StackTrace);
                        if (ue.InnerException != null)
                        {
                            AppModel.LogEntry("[EX] Unhandled Inner Exception: " + ue.InnerException.Message);
                            AppModel.LogEntry(ue.InnerException.StackTrace);
                        }
                    }
                }
                else
                {
                    //another instance running
                    MetroMessageBox.MetroShow(String.Empty, "Another Instance of Shoozla is running", true, App.MainView, MessageIcon.Error);
                    AppModel.LogEntry("[EX] another Instance of Shoozla is running");
                }
            }

            Tracer.Flush();
            Tracer.Close();
            this.Shutdown();

        }


        private void FindCoverSearchersAddIn()
        {

            AppModel.AvailableCoverSearchers = new List<DataModel.CoverSearcher>();
            try
            {
                //search for each DLL that implement the abstract class CoverSearcher
                String currentFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                String[] addiInAssemblies = Directory.GetFiles(currentFolder, "*.dll");

                List<Type> AddInTypes = new List<Type>();

                foreach (String file in addiInAssemblies)
                {
                    Assembly possibleAddIn = Assembly.LoadFrom(file);
                    foreach (Type t in possibleAddIn.GetExportedTypes())
                    {
                        if (t.IsClass && typeof(CoverSearcher).IsAssignableFrom(t) && !t.IsAbstract)
                            AddInTypes.Add(t);
                    }

                }

                //now we have all the types that implements the base class

                foreach (Type t in AddInTypes)
                {
                    CoverSearcher cs = (CoverSearcher)Activator.CreateInstance(t, new object[] { AppModel.CoverImageCache, AppModel.MainCancellationTokenSource, App.StatisticLogger });
                    AppModel.AvailableCoverSearchers.Add(cs);
                    cs.Completed += new EventHandler<ProgressOperationEventArgs>(AppModel.IProgressOperation_SearchCompleted);
                    cs.Started += new EventHandler<ProgressOperationEventArgs>(AppModel.IProgressOperation_SearchStarted);
                 // cs.ProgressChanged += new  EventHandler<ProgressOperationEventArgs>(AppModel.CoverSearcher_CoverFound);
                    cs.NotifyUser += new CoverSearcher.UserInteraction(AppModel.CoverSearcher_NotifyUser);
                    AppModel.LogEntry("Search add-in found: " + cs.AddInName);
                }

                //assign the first found as default
                if (AppModel.AvailableCoverSearchers.Count > 0)
                {
                    AppModel.CoverSearcher = AppModel.AvailableCoverSearchers[0];
                }
                else
                {
                    throw new Exception("No search add-ins");
                }
            }
            catch (Exception e)
            {
                AppModel.LogEntry("[EX] No search add-in, closing the application" );
                AppModel.LogEntry("[EX] " + e.Message);
                MetroMessageBox.MetroShow(String.Empty, "Shoozla cannot start because it didn't find any available add-in, please reinstall the application", true, App.MainView, MessageIcon.Error);                
                this.Shutdown();
            }
        }
     
        public static StartingMode CheckStartingMode()
        {
            //no parameters --> VISUAL

            String[] pars = System.Environment.GetCommandLineArgs();
            if (pars.Length <= 1)
                return StartingMode.Visual; //first parameter is always the file name
            else
                return StartingMode.Background;
        }

        public static void StartUI()
        {

            FolderView = new FolderListView();
            MainView = new MainView(); //this depends from the previous view
           
            AppModel.Songs = new ObservableCollection<Mp3File>();
            var viewModel = MainView.DataContext as MainViewModel;
            MainView.DataContext = viewModel;

            try
            {
                AppModel.LogEntry("MAIN UI thread:" + Thread.CurrentThread.ManagedThreadId);
                MainView.ShowDialog();
            }
            catch (Exception ex)
            {
                AppModel.LogEntry("[ERROR]: App: Generic Error: " + ex.Message);
                //TaskDialogClass.TaskDialog(
                //      new System.Windows.Interop.WindowInteropHelper((Window)App.MainView).Handle,
                //      IntPtr.Zero, "Shoozla","Generic Error", "Check internet connection\n " + ex.Message, 
                //      TaskDialogButtons.OK,
                //      TaskDialogIcon.SecurityError
                //       );

                MetroMessageBox.MetroShow(String.Empty, "An exception occured, chek the log file for more info", true, App.MainView, MessageIcon.Error);
                throw;
            }

        }
      
        public static void StartBackground()
        {
            //i.e: command line or scheduled task
            //parameters:
            // folder - path of the folder to check

            String[] pars = System.Environment.GetCommandLineArgs();

            if (pars.Length != 2)
                ShowUsage();

            DirectoryInfo folder = GetFolderName(pars);
            if (folder == null)
                return;
            try
            {
                if (!EventLog.SourceExists(EventSourceName))
                {
                    EventLog.CreateEventSource(EventSourceName, "Application");
                    EventSourceCreated = true;
                }
                AppModel.LogEvent("Shoozla started on " + folder.FullName, false, 1);
            }
            catch (InvalidOperationException invalidOp)
            {
                AppModel.LogEntry("[ERROR] StartBackground: Cannot create event source");
            }
            catch (Exception e)
            {
                AppModel.LogEntry("[ERROR] StartBackground: " + e.Message);
            }
            finally
            {
                BatchSearch.StartBatchSearch(folder);
            }
        }

        private static DirectoryInfo GetFolderName(string[] args)
        {
            string folderName = args[1];

            if (!Directory.Exists(folderName))
            {
                AppModel.LogEntry(string.Format("Folder: \"{0}\" not found.", folderName));
                return null;
            }

            return new DirectoryInfo(folderName);
        }

        private static void ShowUsage()
        {
            AppModel.LogEntry("usage: shoozla FolderName");
        }

      
    }
}
